﻿using DevExpress.ExpressApp.DC;
using EasyXaf.LowCode.WorkflowEditors.Models;
using EasyXaf.LowCode.WorkflowEditors.Models.Activities;
using System.ComponentModel;
using System.Xml.Linq;

namespace EasyXaf.Sample.Module.BusinessObjects;

[DomainComponent]
[XafDisplayName("创建JSON对象")]
public class CreateJsonObjectActivity : Activity
{
    private string _propertiesXml;

    public string Name
    {
        get => GetPropertyValue<string>();
        set => SetPropertyValue(value);
    }

    public string Description
    {
        get => GetPropertyValue<string>();
        set => SetPropertyValue(value);
    }

    public override bool HasDetailView => true;

    public ObjectCollection<JsonObjectProperty> Properties { get; }

    public CreateJsonObjectActivity(IWorkflow workflow, ISequence sequence)
        : base(workflow, sequence)
    {
        Caption = "创建JSON对象";
        DetailViewScale = 3;

        Properties = new ObjectCollection<JsonObjectProperty>(this);
        Properties.PropertyChanging += Properties_PropertyChanging;
        ((INotifyPropertyChanged)Properties).PropertyChanged += Properties_PropertyChanged;
    }

    private void Properties_PropertyChanging(object sender, PropertyChangingEventArgs e)
    {
        if (!IsUpdateLocked)
        {
            RaisePropertyChanging(nameof(Properties));
        }
    }

    private void Properties_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        _propertiesXml = WritePropertiesToXml(new XElement(GetType().Name));
        if (!IsUpdateLocked)
        {
            RaisePropertyChanged(nameof(Properties));
        }
    }

    private string WritePropertiesToXml(XElement element)
    {
        if (Properties.Any())
        {
            var propertiesElement = new XElement(nameof(Properties));
            element.Add(propertiesElement);
            foreach (var property in Properties)
            {
                var propertyElement = new XElement(property.GetType().Name);
                property.WriteToXml(propertyElement);
                propertiesElement.Add(propertyElement);
            }
        }
        return element.ToString();
    }

    private string ReadPropertiesFromXml(XElement element)
    {
        if (element.Element(nameof(Properties)) is XElement propertiesElement)
        {
            foreach (var propertyElement in propertiesElement.Elements())
            {
                var objectProperty = new JsonObjectProperty();
                objectProperty.ReadFromXml(propertyElement);
                Properties.Add(objectProperty);
            }
            return propertiesElement.ToString();
        }
        return string.Empty;
    }

    public override object GetMemberValue(IMemberInfo memberInfo)
    {
        if (memberInfo.Name == nameof(Properties))
        {
            return _propertiesXml;
        }
        return base.GetMemberValue(memberInfo);
    }

    protected override void SetMemberValueCore(IMemberInfo memberInfo, object value)
    {
        if (memberInfo.Name == nameof(Properties))
        {
            Properties.Clear();
            var valueText = value as string;
            if (!string.IsNullOrWhiteSpace(valueText))
            {
                var element = XElement.Parse(valueText);
                ReadPropertiesFromXml(element);
            }
        }
        else
        {
            base.SetMemberValueCore(memberInfo, value);
        }
    }

    public override void WriteStateToXml(XElement element)
    {
        base.WriteStateToXml(element);

        SetXmlValue(element, nameof(Name), Name);
        SetXmlValue(element, nameof(Description), Description);
    }

    public override void ReadStateFromXml(XElement element)
    {
        base.ReadStateFromXml(element);

        Name = GetXmlValue<string>(element, nameof(Name));
        Description = GetXmlValue<string>(element, nameof(Description));
    }

    public override void WriteToXml(XElement element)
    {
        base.WriteToXml(element);

        WritePropertiesToXml(element);
    }

    public override void ReadFromXml(XElement element)
    {
        base.ReadFromXml(element);

        _propertiesXml = ReadPropertiesFromXml(element);
    }
}
